package com.empire.framework.common.util.http;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * OKHttp工具类（修复SSLSocketFactory抽象方法实现，支持忽略SSL+强制RSA套件）
 */
public class OkHttpUtil {
    private static final Logger log = LoggerFactory.getLogger(OkHttpUtil.class);

    // -------------------------- 统一 MediaType 定义 --------------------------
    public static final MediaType MEDIA_TYPE_FORM = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
    public static final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain; charset=utf-8");

    // -------------------------- 可外部配置的参数 --------------------------
    private static final Integer TIMEOUT = getConfig("okHttp.timeout", 60);
    private static final Integer MAX_POOL_SIZE = getConfig("okHttp.pool.maxPoolSize", 200);
    private static final Integer KEEP_ALIVE_DURATION = getConfig("okHttp.pool.keepAliveDuration", 5);

    // 单例实例与 OkHttpClient 核心对象
    private static OkHttpUtil instance;
    private static OkHttpClient okHttpClient;

    private OkHttpUtil() {}

    /**
     * 单例获取（双重校验锁）
     */
    public static OkHttpUtil getInstance() {
        if (instance == null) {
            synchronized (OkHttpUtil.class) {
                if (instance == null) {
                    initOkHttpClient();
                    instance = new OkHttpUtil();
                }
            }
        }
        return instance;
    }

    /**
     * 初始化 OkHttpClient（含忽略SSL + RSA套件配置）
     */
    private static void initOkHttpClient() {
        okHttpClient = new OkHttpClient.Builder()
                .sslSocketFactory(sslSocketFactory(), x509TrustManager())
                .hostnameVerifier((hostname, session) -> true)
                .retryOnConnectionFailure(false)
                .connectionPool(new ConnectionPool(MAX_POOL_SIZE, KEEP_ALIVE_DURATION, TimeUnit.SECONDS))
                .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
                .build();
        log.info("OkHttpClient 初始化完成：超时={}秒，最大线程池={}，空闲时间={}秒（RSA套件+忽略SSL）",
                TIMEOUT, MAX_POOL_SIZE, KEEP_ALIVE_DURATION);
    }

    // -------------------------- SSL 配置（修复抽象方法实现） --------------------------
    /**
     * 信任所有证书的 TrustManager
     */
    private static X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) {}
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) {}
            @Override
            public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        };
    }

    /**
     * 完整实现 SSLSocketFactory（覆盖所有抽象方法，强制RSA套件）
     */
    private static SSLSocketFactory sslSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());

            // 仅支持的 RSA 加密套件（禁用EC套件）
            final String[] RSA_ONLY_CIPHER_SUITES = {
                    "TLS_RSA_WITH_AES_256_GCM_SHA384",
                    "TLS_RSA_WITH_AES_128_GCM_SHA256",
                    "TLS_RSA_WITH_AES_256_CBC_SHA256",
                    "TLS_RSA_WITH_AES_128_CBC_SHA256"
            };

            // 完整实现 SSLSocketFactory，覆盖所有抽象方法
            return new SSLSocketFactory() {
                // 1. 父类 SocketFactory 抽象方法：创建无连接的Socket
                @Override
                public Socket createSocket() throws IOException {
                    SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket();
                    socket.setEnabledCipherSuites(RSA_ONLY_CIPHER_SUITES);
                    return socket;
                }

                // 2. 父类 SocketFactory 抽象方法：通过主机名和端口创建Socket
                @Override
                public Socket createSocket(String host, int port) throws IOException {
                    SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(host, port);
                    socket.setEnabledCipherSuites(RSA_ONLY_CIPHER_SUITES);
                    log.debug("创建RSA套件Socket：host={}，port={}", host, port);
                    return socket;
                }

                // 3. 父类 SocketFactory 抽象方法：通过InetAddress和端口创建Socket
                @Override
                public Socket createSocket(InetAddress host, int port) throws IOException {
                    SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(host, port);
                    socket.setEnabledCipherSuites(RSA_ONLY_CIPHER_SUITES);
                    return socket;
                }

                // 4. 父类 SocketFactory 抽象方法：带本地地址的Socket创建
                @Override
                public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
                    SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(host, port, localHost, localPort);
                    socket.setEnabledCipherSuites(RSA_ONLY_CIPHER_SUITES);
                    return socket;
                }

                // 5. 父类 SocketFactory 抽象方法：带本地InetAddress的Socket创建
                @Override
                public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
                    SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort);
                    socket.setEnabledCipherSuites(RSA_ONLY_CIPHER_SUITES);
                    return socket;
                }

                // 6. SSLSocketFactory 抽象方法：基于现有Socket创建（OkHttp核心调用）
                @Override
                public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
                    SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
                    sslSocket.setEnabledCipherSuites(RSA_ONLY_CIPHER_SUITES);
                    log.debug("基于现有Socket创建RSA套件连接：host={}，port={}", host, port);
                    return sslSocket;
                }

                // 7. 获取默认加密套件（返回RSA套件）
                @Override
                public String[] getDefaultCipherSuites() {
                    return RSA_ONLY_CIPHER_SUITES;
                }

                // 8. 获取支持的加密套件（返回RSA套件）
                @Override
                public String[] getSupportedCipherSuites() {
                    return RSA_ONLY_CIPHER_SUITES;
                }
            };

        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            log.error("初始化 SSLSocketFactory 失败", e);
            throw new RuntimeException("SSL 配置异常", e);
        }
    }

    // -------------------------- 核心请求方法（保持不变） --------------------------
    public String postJson(String api, Object params) {
        return postJson(api, params, null);
    }

    public String postJson(String api, Object params, Map<String, String> headerMap) {
        MediaType mediaType = MEDIA_TYPE_JSON;
        String jsonParams = (params == null) ? "{}" : JSONObject.toJSONString(params);
        RequestBody requestBody = RequestBody.create(mediaType, jsonParams);

        Request.Builder builder = new Request.Builder()
                .url(api)
                .post(requestBody)
                .addHeader("Connection", "close");

        addHeadersToBuilder(builder, headerMap);

        log.info("发起 postJson 请求：url={}，Content-Type={}，请求体={}",
                api, mediaType.toString(), maskSensitiveJson(jsonParams));

        return executeRequest(builder.build(), api);
    }

    public String postForm(String url, Map<String, Object> params) {
        if (params == null || params.isEmpty()) {
            throw new IllegalArgumentException("表单请求参数不能为空");
        }

        FormBody.Builder formBuilder = new FormBody.Builder();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String value = (entry.getValue() == null) ? "" : entry.getValue().toString();
            formBuilder.add(entry.getKey(), value);
        }

        Request request = new Request.Builder()
                .url(url)
                .post(formBuilder.build())
                .addHeader("Connection", "close")
                .addHeader("Content-Type", MEDIA_TYPE_FORM.toString())
                .build();

        log.info("发起 postForm 请求：url={}，参数={}", url, params);
        return executeRequest(request, url);
    }

    public String get(String api, Map<String, Object> params, Map<String, String> headerMap) {
        try {
            String requestUrl = buildGetUrl(api, params);
            Request.Builder builder = new Request.Builder()
                    .url(requestUrl)
                    .get()
                    .addHeader("Connection", "close");

            addHeadersToBuilder(builder, headerMap);
            Request request = builder.build();

            log.info("发起 get 请求：url={}", requestUrl);
            return executeRequest(request, api);
        } catch (UnsupportedEncodingException e) {
            log.error("get 请求 URL 编码失败", e);
            throw new RuntimeException("URL 编码异常", e);
        }
    }

    public InputStream getForStream(String api, Map<String, Object> params, Map<String, String> headerMap) {
        try {
            String requestUrl = buildGetUrl(api, params);
            Request.Builder builder = new Request.Builder()
                    .url(requestUrl)
                    .get()
                    .addHeader("Connection", "close");

            addHeadersToBuilder(builder, headerMap);
            Request request = builder.build();

            log.info("发起 getForStream 请求：url={}", requestUrl);
            return executeRequestForStream(request, api);
        } catch (UnsupportedEncodingException e) {
            log.error("getForStream 请求 URL 编码失败", e);
            throw new RuntimeException("URL 编码异常", e);
        }
    }

    // -------------------------- 通用工具方法（保持不变） --------------------------
    private String executeRequest(Request request, String api) {
        try (Response response = okHttpClient.newCall(request).execute()) {
            if (response.isSuccessful()) {
                ResponseBody body = response.body();
                if (body == null) {
                    log.warn("请求成功但响应体为空：url={}", api);
                    return null;
                }
                String responseBody = body.string();
                log.info("请求成功：url={}，响应码={}，响应体={}",
                        api, response.code(), maskSensitiveJson(responseBody));
                return responseBody;
            } else {
                String errorBody = (response.body() != null) ? response.body().string() : "无响应体";
                log.error("请求失败：url={}，响应码={}，错误信息={}",
                        api, response.code(), errorBody);
                throw new RuntimeException(String.format("请求失败：响应码=%d，错误信息=%s",
                        response.code(), errorBody));
            }
        } catch (IOException e) {
            log.error("请求 IO 异常：url={}", api, e);
            throw new RuntimeException("网络请求异常：" + e.getMessage(), e);
        }
    }

    private InputStream executeRequestForStream(Request request, String api) {
        try {
            Response response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                ResponseBody body = response.body();
                if (body == null) {
                    log.warn("流式请求成功但响应体为空：url={}", api);
                    response.close();
                    return null;
                }
                log.info("流式请求成功：url={}，响应码={}", api, response.code());
                return body.byteStream();
            } else {
                String errorBody = (response.body() != null) ? response.body().string() : "无响应体";
                log.error("流式请求失败：url={}，响应码={}，错误信息={}",
                        api, response.code(), errorBody);
                response.close();
                throw new RuntimeException(String.format("流式请求失败：响应码=%d，错误信息=%s",
                        response.code(), errorBody));
            }
        } catch (IOException e) {
            log.error("流式请求 IO 异常：url={}", api, e);
            throw new RuntimeException("流式网络请求异常：" + e.getMessage(), e);
        }
    }

    private void addHeadersToBuilder(Request.Builder builder, Map<String, String> headerMap) {
        if (headerMap == null || headerMap.isEmpty()) {
            return;
        }
        for (Map.Entry<String, String> entry : headerMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (key == null || value == null) {
                log.debug("跳过 null 值请求头：key={}，value={}", key, value);
                continue;
            }
            if ("Connection".equalsIgnoreCase(key) && "close".equalsIgnoreCase(value)) {
                continue;
            }
            if ("Content-Type".equalsIgnoreCase(key)) {
                log.debug("跳过手动 Content-Type：{}", value);
                continue;
            }
            builder.addHeader(key, value);
        }
    }

    private String buildGetUrl(String api, Map<String, Object> params) throws UnsupportedEncodingException {
        if (params == null || params.isEmpty()) {
            return api;
        }
        StringBuilder paramBuilder = new StringBuilder(api).append("?");
        int index = 0;
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (key == null || value == null) {
                continue;
            }
            if (index > 0) {
                paramBuilder.append("&");
            }
            paramBuilder.append(String.format("%s=%s",
                    key, URLEncoder.encode(value.toString(), "UTF-8")));
            index++;
        }
        return paramBuilder.toString();
    }

    private String maskSensitiveJson(String json) {
        if (json == null) {
            return null;
        }
        json = json.replaceAll("\"idcard\":\"(\\d{6})\\d+(\\d{4})\"", "\"idcard\":\"$1****$2\"");
        json = json.replaceAll("\"mobile\":\"(\\d{3})\\d+(\\d{4})\"", "\"mobile\":\"$1****$2\"");
        return json;
    }

    private static Integer getConfig(String key, Integer defaultValue) {
        return defaultValue;
    }

    // -------------------------- 文件上传方法（保持不变） --------------------------
    public String postFile(String url, Map<String, String> params, File file, String fileKey) {
        if (file == null || !file.exists()) {
            throw new IllegalArgumentException("上传文件不存在");
        }
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        RequestBody body = RequestBody.create(file, MEDIA_TYPE_FORM);
        requestBody.addFormDataPart(fileKey, file.getName(), body);
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                requestBody.addFormDataPart(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder().url(url).post(requestBody.build()).build();
        log.info("发起 postFile 请求：url={}，fileName={}", url, file.getName());
        try {
            return executeRequest(request, url);
        } finally {
            okHttpClient.connectionPool().evictAll();
        }
    }

    public String postFileByte(String url, Map<String, String> params, String filename, byte[] file, String fileKey) {
        if (file == null || file.length == 0) {
            throw new IllegalArgumentException("上传文件字节为空");
        }
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        RequestBody body = RequestBody.create(file, MEDIA_TYPE_FORM);
        requestBody.addFormDataPart(fileKey, filename, body);
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                requestBody.addFormDataPart(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder().url(url).post(requestBody.build()).build();
        log.info("发起 postFileByte 请求：url={}，filename={}", url, filename);
        try {
            return executeRequest(request, url);
        } finally {
            okHttpClient.connectionPool().evictAll();
        }
    }
}